# 👌 Awesome built-in UI

CamerAwesome comes with a full built UI that you can use as is.

Use `CameraAwesomeBuilder.awesome()` to get a complete ready-to-use camera experience within your app.

Here is a concrete example using **path_provider** to get valid paths and **better_open_file** to display the last media captured:

```dart
CameraAwesomeBuilder.awesome(
  saveConfig: SaveConfig.photoAndVideo(
    photoPathBuilder: () async {
      final Directory extDir = await getTemporaryDirectory();
      final testDir =
          await Directory('${extDir.path}/test').create(recursive: true);
      return '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg';
    },
    videoPathBuilder: () async {
      final Directory extDir = await getTemporaryDirectory();
      final testDir =
          await Directory('${extDir.path}/test').create(recursive: true);
      return '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.mp4';
    },
    onMediaTap: (mediaCapture) {
      OpenFile.open(mediaCapture.filePath);
    },
  ),
)
```

![Base Awesome UI](/img/base_awesome_ui.jpg)

## 📷 Initial Camera setup

You can set the initial camera configuration using the `CameraAwesomeBuilder` parameters.

```dart
CameraAwesomeBuilder.awesome(
  aspectRatio: CameraAspectRatios.ratio_1_1,
  enableAudio: true,
  exifPreferences: ExifPreferences(
    saveGPSLocation: false,
  ),
  filter: Filters.none,
  flashMode: FlashMode.none,
  onMediaTap: (mediaCapture) {
    print('Tap on ${mediaCapture.filePath}');
  },
  saveConfig: SaveConfig.photoAndVideo(
    initialCaptureMode: CaptureMode.photo,
    photoPathBuilder: () async {
      return 'some/image/file/path.jpg';
    },
    videoPathBuilder: () async {
      return 'some/video/file/path.mp4';
    },
  ),
  sensor: Sensors.back,
  zoom: 0.0,
  // Other parameters
  ...
)
```

| Parameter           | Description                                                                                                 |
| ------------------- | ----------------------------------------------------------------------------------------------------------- |
| **aspectRatio**     | Initial aspect ratio of photos and videos taken                                                             |
| **enableAudio**     | Activate audio by default (only for video mode)                                                             |
| **exifPreferences** | Activate or deactivate location in photo exif                                                               |
| **filter**          | Initial preview filter which will be applied to the photo                                                   |
| **flashMode**       | The initial flash mode                                                                                      |
| **onMediaTap**      | Choose what you want to do when user tap on the last media captured (when using the built-in image preview) |
| **saveConfig**      | Define if you want to take photos, videos or both and where to save them                                    |
| **sensor**          | The initial camera sensor (Back or Front)                                                                   |
| **zoom**            | A value between 0.0 (no zoom) and 1.0 (max zoom)                                                            |

## 🎨 Customize the built-in UI

Several parameters let you customize the built-in UI.

### Theming

You can customize the look and feel of CamerAwesome's built-in UI by setting your own theme.

For example, buttons are black with a white icon and they bounce when you tap them.

You can completely change them with `AwesomeTheme`:

Example:

```dart
CameraAwesomeBuilder.awesome(
  theme: AwesomeTheme(
    // Background color of the bottom actions
    bottomActionsBackgroundColor: Colors.deepPurple.withOpacity(0.5),
    // Buttons theme
    buttonTheme: AwesomeButtonTheme(
      // Background color of the button
      backgroundColor: Colors.deepPurple.withOpacity(0.5),
      // Size of the icon
      iconSize: 32,
      // Padding around the icon
      padding: const EdgeInsets.all(18),
      // Color of the icon
      foregroundColor: Colors.lightBlue,
      // Tap visual feedback (ripple, bounce...)
      buttonBuilder: (child, onTap) {
        return ClipOval(
          child: Material(
            color: Colors.transparent,
            shape: const CircleBorder(),
            child: InkWell(
              splashColor: Colors.deepPurple,
              highlightColor: Colors.deepPurpleAccent.withOpacity(0.5),
              onTap: onTap,
              child: child,
            ),
          ),
        );
      },
    ),
  ),
);
```

![Custom theme](/img/custom_theme.gif)

Let's see what happens in the above animation:

- In the first part, the default theme of CamerAwesome is used. Note that the Flash button bounces when tapped.
- Then, the code is changed to show the custom theme above with a hot reload.
- Finally, the UI is updated with the new purple theme and you can see that even the Flash button has a different tap effect: it is now a ripple.

If you are using the built-in UI - even partially, it is recommended to use `AwesomeTheme` in the rest of your Camera UI to stay consistent.

You can access the current `AwesomeTheme` by using `AwesomeThemeProvider`:

```dart
final myTheme = AwesomeThemeProvider.of(context).theme
```

**Tip:** If you don't have a `BuildContext` to access the parent's `AwesomeTheme`, wrap your widget within a `Builder` widget.

See also [Theming](/widgets/theming) and `custom_theme.dart` for an example with a custom theme.

### Place widgets in your UI

The built-in UI is separated in 3 areas:

![Awesome UI parts](/img/awesome_ui_parts.webp)

1. Top actions built with `topActionsBuilder`
2. Middle content built with `middleContentBuilder`
3. Bottom actions built with `bottomActionsBuilder`

You can customize each builder to return the elements that you want in each part.
Feel free to reuse the included build-in widgets (aspect ratio button, flash button...).

Here is an example of what you can do:

```dart
CameraAwesomeBuilder.awesome(
  // Other parameters
  ...
  // Set an AwesomeTheme that you might reuse in your UI
  theme: AwesomeTheme(
    bottomActionsBackgroundColor: Colors.cyan.withOpacity(0.5),
    buttonTheme: AwesomeButtonTheme(
      backgroundColor: Colors.cyan.withOpacity(0.5),
      iconSize: 20,
      foregroundColor: Colors.white,
      padding: const EdgeInsets.all(16),
      // Tap visual feedback (ripple, bounce...)
      buttonBuilder: (child, onTap) {
        return ClipOval(
          child: Material(
            color: Colors.transparent,
            shape: const CircleBorder(),
            child: InkWell(
              splashColor: Colors.cyan,
              highlightColor: Colors.cyan.withOpacity(0.5),
              onTap: onTap,
              child: child,
            ),
          ),
        );
      },
    ),
  ),
  // Show the filter button on the top part of the screen
  topActionsBuilder: (state) => AwesomeTopActions(
    padding: EdgeInsets.zero,
    state: state,
    children: [
      Expanded(
        child: AwesomeFilterWidget(
          state: state,
          filterListPosition: FilterListPosition.aboveButton,
          filterListPadding: const EdgeInsets.only(top: 8),
        ),
      ),
    ],
  ),
  // Show some Text with same background as the bottom part
  middleContentBuilder: (state) {
    return Column(
      children: [
        const Spacer(),
        // Use a Builder to get a BuildContext below AwesomeThemeProvider widget
        Builder(builder: (context) {
          return Container(
            // Retrieve your AwesomeTheme's background color
            color: AwesomeThemeProvider.of(context)
                .theme
                .bottomActionsBackgroundColor,
            child: const Align(
              alignment: Alignment.bottomCenter,
              child: Padding(
                padding: EdgeInsets.only(bottom: 10, top: 10),
                child: Text(
                  "Take your best shot!",
                  style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                    fontStyle: FontStyle.italic,
                  ),
                ),
              ),
            ),
          );
        }),
      ],
    );
  },
  // Show Flash button on the left and Camera switch button on the right
  bottomActionsBuilder: (state) => AwesomeBottomActions(
    state: state,
    left: AwesomeFlashButton(
      state: state,
    ),
    right: AwesomeCameraSwitchButton(
      state: state,
      scale: 1.0,
      onSwitchTap: (state) {
        state.switchCameraSensor(
          aspectRatio: state.sensorConfig.aspectRatio,
        );
      },
    ),
  ),
)
```

![Custom awesome UI](/img/custom_awesome_ui.jpg)

| Parameter                | Description                                             |
| ------------------------ | ------------------------------------------------------- |
| **topActionsBuilder**    | Top part of the built-in UI                             |
| **middleContentBuilder** | Content between top and bottom parts of the built-in UI |
| **bottomActionsBuilder** | Bottom part of the built-in UI                          |

See `custom_awesome_ui.dart` for an example using these parameters.

### Camera preview positioning

Use these parameters to adjust where you want to place the camera preview in your UI.

```dart
CameraAwesomeBuilder.awesome(
  previewPadding: const EdgeInsets.all(20),
  previewAlignment: Alignment.center,
  // Other parameters
  ...
)
```

![Custom preview positioning](/img/camera_preview_position.jpg)

By default, preview is centered with no padding.

| Parameter            | Description                    |
| -------------------- | ------------------------------ |
| **previewPadding**   | Add padding around the preview |
| **previewAlignment** | Align the preview              |

You can see these parameters in use in `custom_awesome_ui.dart` example.

### Add additional content on top of the preview

If you'd like to place elements on top of the preview, like you would do it in a Stack, use the `previewDecoratorBuilder`.

This feature can be used combined with image analysis to show face filters (like snapchat ones) for example:

![Face filter using previewDecoratorBuilder](/img/face_filter.jpg)

| Parameter                   | Description                        |
| --------------------------- | ---------------------------------- |
| **previewDecoratorBuilder** | Add a widget on top of the preview |

That's what is used in `ai_analysis_faces.dart` to draw contours of the detected face.

## 📝 Complete example

Here is an example showing the complete list of parameters you can set to customize your camera experience:

```dart
CameraAwesomeBuilder.awesome(
  // Define if you want to take photos, videos or both and where to save them
  saveConfig: SaveConfig.photoAndVideo(
    initialCaptureMode: CaptureMode.photo,
    photoPathBuilder: () async {
      // Return a valid file path (must be a jpg file)
      return 'some/image/file/path.jpg';
    },
    videoPathBuilder: () async {
      // Return a valid file path (must be a mp4 file)
      return 'some/video/file/path.mp4';
    },
  ),
  onMediaTap: (mediaCapture) {
    // Hande tap on the preview of the last media captured
    print('Tap on ${mediaCapture.filePath}');
  },
  // Use back camera
  sensor: Sensors.back,
  // Use 1:1 aspect ratio
  aspectRatio: CameraAspectRatios.ratio_1_1,
  // Disable flash
  flashMode: FlashMode.none,
  // No zoom
  zoom: 0.0,
  // Exif settings
  exifPreferences: ExifPreferences(
    // Save GPS location when taking pictures (no effect with videos)
    saveGPSLocation: false,
  ),
  // Enable audio when recording a video
  enableAudio: true,
  // Clicking on volume buttons will capture photo/video depending on the current mode
  enablePhysicalButton: true,
  // Don't mirror the front camera
  mirrorFrontCamera: false,
  // Show a progress indicator while loading the camera
  progressIndicator: const Center(
    child: SizedBox(
      width: 100,
      height: 100,
      child: CircularProgressIndicator(),
    ),
  ),
  // Preview fit of the camera
  previewFit: CameraPreviewFit.fitWidth,
  // Image analysis configuration
  imageAnalysisConfig: AnalysisConfig(
        androidOptions: const AndroidAnalysisOptions.nv21(
            width: 1024,
        ),
        autoStart: true,
  ),
  // Handle image analysis
  onImageForAnalysis: (analysisImage) {
    // Do some stuff with the image (see example)
    return processImage(analysisImage);
  },
  // Handle gestures on the preview, such as tap to focus or scale to zoom
  onPreviewTapBuilder: (state) => OnPreviewTap(
    onTap: (position, flutterPreviewSize, pixelPreviewSize) {
      // Handle tap to focus (default) or take a photo for instance
      // ...
    },
    onTapPainter: (position) {
      // Tap feedback, here we just show a circle
      return Positioned(
        left: position.dx - 25,
        top: position.dy - 25,
        child: IgnorePointer(
          child: Container(
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              border: Border.all(color: Colors.white, width: 2),
            ),
            width: 50,
            height: 50,
          ),
        ),
      );
    },
    // Duration during which the feedback should be shown
    tapPainterDuration: const Duration(seconds: 2),
  ),
  // Handle scale gestures on the preview
  onPreviewScaleBuilder: (state) => OnPreviewScale(
    onScale: (scale) {
      // Do something with the scale value, set zoom for instance
      state.sensorConfig.setZoom(scale);
    },
  ),
  // Add your own decoration on top of the preview
  previewDecoratorBuilder: (state, previewSize, previewRect) {
    // This will be shown above the preview (in a Stack)
    // It could be used in combination with MLKit to draw filters on faces for example
    return PreviewDecorationWiget(previewRect);
  },
  // CamerAwesome theme used to customize the built-in UI
  theme: AwesomeTheme(
    // Background color of the bottom actions
    bottomActionsBackgroundColor: Colors.deepPurple.withOpacity(0.5),
    // Buttons theme
    buttonTheme: AwesomeButtonTheme(
      // Background color of the buttons
      backgroundColor: Colors.deepPurple.withOpacity(0.5),
      // Buttons icon size
      iconSize: 32,
      // Padding around icons
      padding: const EdgeInsets.all(18),
      // Buttons icon color
      foregroundColor: Colors.lightBlue,
      // Tap visual feedback (ripple, bounce...)
      buttonBuilder: (child, onTap) {
        return ClipOval(
          child: Material(
            color: Colors.transparent,
            shape: const CircleBorder(),
            child: InkWell(
              splashColor: Colors.deepPurple,
              highlightColor: Colors.deepPurpleAccent.withOpacity(0.5),
              onTap: onTap,
              child: child,
            ),
          ),
        );
      },
    ),
  ),
  // Filter to apply on the preview
  filter: AwesomeFilter.AddictiveRed,
  // Padding around the preview
  previewPadding: const EdgeInsets.all(20),
  // Alignment of the preview
  previewAlignment: Alignment.center,
  // Bottom actions (take photo, switch camera...)
  bottomActionsBuilder: (state) {
    return AwesomeBottomActions(
      state: state,
      onMediaTap: _handleMediaTap,
    );
  },
  // Top actions (flash, timer...)
  topActionsBuilder: (state) {
    return AwesomeTopActions(state: state);
  },
  // Middle content (filters, photo/video switcher...)
  middleContentBuilder: (state) {
    // Use this to add widgets on the middle of the preview
    return Column(
      children: [
        const Spacer(),
        AwesomeFilterWidget(state: state),
        Builder(
          builder: (context) => Container(
            color: AwesomeThemeProvider.of(context)
                .theme
                .bottomActionsBackgroundColor,
            height: 8,
          ),
        ),
        AwesomeCameraModeSelector(state: state),
      ],
    );
  },
)
```

### 🔬 Full list of properties

| Method                      | Comment                                                                                                                                               |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **aspectRatio**             | Initial aspect ratio of photos and videos taken                                                                                                       |
| **bottomActionsBuilder**    | A widget builder used to show buttons on the bottom of the preview.<br/>`AwesomeBottomActions` by default.                                            |
| **enableAudio**             | Activate audio by default (only for video mode)                                                                                                       |
| **enablePhysicalButton**    | When set to true, volume buttons will capture pictures/videos depending on the current mode.                                                          |
| **exifPreferences**         | Activate or deactivate location in photo exif                                                                                                         |
| **filter**                  | Initial preview filter which will be applied to the photo                                                                                             |
| **flashMode**               | The initial flash mode                                                                                                                                |
| **imageAnalysisConfig**     | Image format, resolution and autoStart (start analysis immediately or later)                                                                          |
| **middleContentBuilder**    | A widget builder used to add widgets above the middle part of the preview (between bottom and top actions).<br/>Shows the filter selector by default. |
| **mirrorFrontCamera**       | Activate to mirror the pictures taken with the front camera                                                                                           |
| **onImageForAnalysis**      | Callback that will provide an image stream for AI analysis                                                                                            |
| **onMediaTap**              | Choose what you want to do when user tap on the last media captured                                                                                   |
| **onPreviewTapBuilder**     | Customize the behavior when the camera preview is tapped (tap to focus by default)                                                                    |
| **onPreviewScaleBuilder**   | Customize what to do when the user makes a pinch (pinch to zoom by default)                                                                           |
| **previewAlignment**        | Alignment of the preview                                                                                                                              |
| **previewDecoratorBuilder** | A widget builder used to draw elements around or on top of the preview                                                                                |
| **previewFit**              | One of fitWidth, fitHeight, contain, cover                                                                                                            |
| **previewPadding**          | Padding around the preview                                                                                                                            |
| **progressIndicator**       | Widget to show when loading                                                                                                                           |
| **saveConfig**              | Define if you want to take photos, videos or both and where to save them                                                                              |
| **sensor**                  | The initial camera sensor (Back or Front)                                                                                                             |
| **theme**                   | Theme used to customize the built-in UI                                                                                                               |
| **topActionsBuilder**       | A widget builder used to show buttons on the top of the preview.<br/>`AwesomeTopActions` by default.                                                  |
| **zoom**                    | A value between 0.0 (no zoom) and 1.0 (max zoom)                                                                                                      |

## 🔨 Need more customization? Other use cases?

If the separation between top, middle and bottom content doesn't suit your needs, you can also provide your own UI using `CameraAwesomeBuilder.custom()` builder.

See [🎨 Creating a custom UI](/getting_started/custom-ui) documentation.

If you only want to display the preview and not taking pictures or videos, you can also use `CameraAwesomeBuilder.previewOnly()` constructor.
You can check [Reading barcodes](image_analysis/reading_barcodes) and [Detecting faces](image_analysis/detecting_faces) examples to see how to use it.

If you are only interested in image analysis, you can also use `CameraAwesomeBuilder.analysisOnly()` which will **not** provide a camera preview behind your `builder`.
In `analysis_image_filter.dart` and `analysis_image_filter_picker.dart`, this constructor is used to draw a camera preview with filter effects applied to each image (image distortion, greyscale, etc...).
You can find more about this example in the [Image analysis formats and conversions documentation](/image_analysis/image_format/conversions).
